<script setup lang="ts">
import { onBeforeUnmount, onMounted, useTemplateRef } from 'vue';
import { createNoise3D } from 'simplex-noise';

/* ---------- 引用 ---------- */
const canvas = useTemplateRef<HTMLCanvasElement>('canvas');

/* ---------- 内部变量 ---------- */
let ctx: CanvasRenderingContext2D;

let rafId: number;
const noise = createNoise3D();

const xCount = 100; // X方向的折点数量，值越大线段越平滑
const yCount = 50; // 线的数量

/* ---------- 绘制 ---------- */
function draw(timeDiff: number): void {
    const ix = 1 / (xCount - 1);
    const iy = 1 / (yCount - 1);
    const time = timeDiff * 0.0001;

    const canvasHeight = canvas.value!.height;
    const canvasWidth = canvas.value!.width;

    /* 0-1 之间来回 */
    const t = Math.abs(Math.sin(time));

    const grad = ctx.createLinearGradient(0, 0, canvasWidth, canvasHeight);
    grad.addColorStop(0, '#ffabab');
    grad.addColorStop(t, '#99bef6');
    grad.addColorStop(1, '#ffabab');

    ctx.fillStyle = grad;
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);

    /* 绘制波浪线条：关键修复——x 坐标直接铺满整个画布宽度，不再留空 */
    ctx.beginPath(); // 清空当前路径，准备绘制一条全新的路径

    let ty = 0, // ty 用于在 0~1 之间均匀步进 y 方向（0 表示顶部，1 表示底部）
        localT = time; // localT 给每一行波浪一个略微错位的时间，避免所有行完全同步

    /* 纵向循环：共 yCount 行波浪，从上到下均匀排列 */
    for (let j = 0; j < yCount; j++, ty += iy, localT += 0.01) {
        // c 是一个小幅度相位偏移，随 ty 和 time 变化，让相邻行波浪形状略有差异
        const c = Math.cos(ty * Math.PI * 2 + time) * 0.1;

        /* 横向循环：共 xCount 个点，从左到右均匀采样 */
        for (let i = 0; i < xCount; i++) {
            const t = i * ix; // t 在 0~1 之间均匀步进 x 方向（0 表示最左边，1 表示最右边）

            // 用 3D Simplex 噪声生成波浪高度；三个维度：横向位置 t、时间 localT、相位偏移 c
            const n = noise(t, localT, c);

            // 把噪声值 n（范围约 -1~1）映射到画布高度的一半，并纵向居中
            const y = (n * canvasHeight) / 2 + canvasHeight / 2;

            // 把归一化的横向位置 t 映射到实际画布像素坐标，确保线条从左到右完全铺满画布
            const x = t * canvasWidth;

            // 第一个点 moveTo，后续点 lineTo，形成连续路径
            i ? ctx.lineTo(x, y) : ctx.moveTo(x, y);
        }
    }

    ctx.lineWidth = 2;
    const hue = (time * 60) % 300; // 数字越大变化越快

    ctx.strokeStyle = `hsl(${hue}, 80%, 55%)`;
    ctx.stroke();
}

/* ---------- 动画 ---------- */
let start = performance.now();

function loop() {
    draw(performance.now() - start);
    rafId = requestAnimationFrame(loop);
}

/* ---------- 生命周期 ---------- */
onMounted(() => {
    ctx = canvas.value!.getContext('2d')!;
    // 清晰度问题
    ctx.imageSmoothingEnabled = false;
    const dpi = window.devicePixelRatio;
    canvas.value!.width = canvas.value!.clientWidth * dpi;
    canvas.value!.height = canvas.value!.clientHeight * dpi;
    loop();
});

onBeforeUnmount(() => {
    cancelAnimationFrame(rafId);
});
</script>
<template>
    <canvas ref="canvas" class="wave-noise" />
</template>

<style scoped>
.wave-noise {
    display: block;
    width: 100%;
    height: 100%;
    background: #000;
}
</style>
